/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.sdt.refinement.generator;

import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDF;
import java.util.List;
import java.util.Vector;
import edu.yonsei.iwb.sdt.algorithm.DCSSearcher;
import edu.yonsei.iwb.sdt.datastructure.tree.BranchingType;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidate;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import edu.yonsei.iwb.sdt.datastructure.TargetInstance;
import edu.yonsei.iwb.sdt.ontology.PropertyArc;
import edu.yonsei.iwb.sdt.refinement.ConjunctionRefinement;
import edu.yonsei.iwb.sdt.refinement.DLConstructors;
import edu.yonsei.iwb.sdt.refinement.ExpandingHistory;
import edu.yonsei.iwb.sdt.refinement.ExpandingHistorySet;
import edu.yonsei.iwb.sdt.refinement.Refinement;
import edu.yonsei.iwb.sdt.refinement.RefinementType;
import edu.yonsei.iwb.sdt.util.SDTLog;
import edu.yonsei.iwb.ts.TSSearch;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author JDK
 */
public class ConjunctionRefinementMaker extends Thread{

    
    private Vector<TargetInstance> instanceSet;
    private String cenclass;
    private String conclass;
    private PropertyArc pa;
    private Vector<PropertyArc> hisPAset;    
    private DecomposeCandidateSet dcs;
    private QuantificationRefinementMaker qrm;

    public ConjunctionRefinementMaker(Vector<TargetInstance> instanceSet) {        
        this.instanceSet = instanceSet;
        this.qrm = new QuantificationRefinementMaker(RefinementType.CONJUNCTION);
    }
    
    public ConjunctionRefinementMaker(String cenclass, String conclass, Vector<TargetInstance> instanceSet, DecomposeCandidateSet dcs) {        
        this.cenclass = cenclass;
        this.conclass = conclass;
        this.instanceSet = instanceSet;
        this.dcs =dcs;        
        this.qrm = new QuantificationRefinementMaker(RefinementType.CONJUNCTION);
    }
    
    public ConjunctionRefinementMaker(String cenclass, String conclass, PropertyArc pa, Vector<PropertyArc> hisPAset , Vector<TargetInstance> instanceSet, DecomposeCandidateSet dcs) {        
        this.cenclass = cenclass;
        this.conclass = conclass;
        this.pa = pa;
        this.hisPAset = hisPAset;                
        this.instanceSet = instanceSet;
        this.dcs =dcs;        
        this.qrm = new QuantificationRefinementMaker(RefinementType.CONJUNCTION);
    }
    
    @Override
    public synchronized void run() {
        try {
            long startTime = System.currentTimeMillis();          
            boolean gen = decomposeCandidateOfCR();
            DCSSearcher.FLAGNUM--;
            long endTime = System.currentTimeMillis();        
            if(gen){
                SDTLog.log(SDTLog.DETAIL,"# CR :  "+this.cenclass +" AND : "+ this.conclass+" is generated..."+((endTime - startTime)/1000.0f)+"s)\n");            
            }else{            
                SDTLog.log(SDTLog.DETAIL,"# - CR :  "+this.cenclass +" AND : "+ this.conclass+" is NOT generated..."+((endTime - startTime)/1000.0f)+"s)\n");            
            }
        } catch (IOException ex) {
            Logger.getLogger(ConjunctionRefinementMaker.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }

    private boolean decomposeCandidateOfCR() throws IOException {
        if (hisPAset == null) {
            // no expand
            Vector<Refinement> refset = this.refinementGenerator(cenclass, conclass);
            if(refset!=null){
                this.dcs.add(new DecomposeCandidate(refset, RefinementType.CONJUNCTION));
                return true;
            }else{
                return false;
            }
        } else {
            DecomposeCandidateSet newdcs = this.refinementGenerator(pa, cenclass, conclass, hisPAset);
            if(newdcs != null){
                this.dcs.addAll(newdcs);
                return true;
            }else{
                return false;
            }
        }
        
    }
    
    public Vector<Refinement> refinementGenerator(String cenclass, String conclass) throws IOException{
        
        Vector<Refinement> rset = new Vector<Refinement>();        
        Vector<TargetInstance> cloneSet = new Vector(instanceSet);
        Vector<TargetInstance> sfTiSet = new Vector();
        
        for (int i = 0; i < this.instanceSet.size(); i++) {
            TargetInstance ti = this.instanceSet.get(i);
            if(ti.checkClassType(cenclass)){
                if(ti.checkClassType(conclass)){
                    sfTiSet.add(ti);
                    cloneSet.remove(ti);
                }
            }
        }
        
        if(!sfTiSet.isEmpty()){
            Refinement pref = new ConjunctionRefinement("", cenclass, conclass);
            pref.setInstanceSet(sfTiSet);
            rset.add(pref);
        }
        
        if(!cloneSet.isEmpty()){
            Refinement nref = new ConjunctionRefinement(DLConstructors.NEGATION, cenclass, conclass);
            nref.setBranchingType(BranchingType.NEGATION_TYPE);
            nref.setInstanceSet(cloneSet);
            rset.add(nref);
        }
        
        return rset;        
    }
    
    /**
     * 
     * @param pa
     * @param centerclass
     * @param conclass
     * @param paSet
     * @return 
     */
    public DecomposeCandidateSet refinementGenerator(PropertyArc pa, String centerclass, String conclass, Vector<PropertyArc> paSet) throws IOException {
                
        Vector<PropertyArc> propertyHistory = new Vector(paSet);
        propertyHistory.add(pa);

        Vector<String> css = getSatisfiedInstanceSet(centerclass, conclass);

        ExpandingHistorySet ehs = this.qrm.expandingHistoryCounter(propertyHistory, css);
        DecomposeCandidateSet dcs = new DecomposeCandidateSet();

        for (int i = 0; i < ehs.size(); i++) {
            ExpandingHistory eh = ehs.get(i);
            Vector<Refinement> refset = new Vector<Refinement>();            

            Vector<String> is = eh.getInstanceSet();
            
            Vector<TargetInstance> cloneSet = new Vector(this.instanceSet);
            Vector<TargetInstance> sfTIset = new Vector();
            
            for (int j = 0; j < is.size(); j++) {
                String result = is.get(j);
                for (int k = 0; k < this.instanceSet.size(); k++) {
                    TargetInstance ti = this.instanceSet.get(k);
                    if(ti.getUri().equals(result)){
                        sfTIset.add(ti);
                        cloneSet.remove(ti);
                    }
                }
            }
            
            if(!sfTIset.isEmpty()){
                Refinement pref = new ConjunctionRefinement("", eh, centerclass, conclass);
                pref.setInstanceSet(sfTIset);
                refset.add(pref);
            }
            
            if(!cloneSet.isEmpty()){
                Refinement nref = new ConjunctionRefinement(DLConstructors.NEGATION, eh, centerclass, conclass);
                nref.setBranchingType(BranchingType.NEGATION_TYPE);
                nref.setInstanceSet(cloneSet);                
                refset.add(nref);
            }
            
            if(!refset.isEmpty()){
                DecomposeCandidate dc = new DecomposeCandidate(refset, pa, RefinementType.CONJUNCTION);
                dcs.add(dc);                
            }
        }
        
        return dcs;
    }

    private Vector<String> getSatisfiedInstanceSet(String cenclass, String conclass) throws IOException {
        Vector<String> css = new Vector<String>();
        
        ArrayList<String> cen = TSSearch.listSubjectResource(RDF.type.getURI(), cenclass);
        ArrayList<String> con = TSSearch.listSubjectResource(RDF.type.getURI(), conclass);
        
        for (int i = 0; i < cen.size(); i++) {            
            if(con.contains(cen.get(i))){
                if(!css.contains(cen.get(i))){
                    css.add(cen.get(i));                    
                }                
            }
        }        

        return css;
    }    
}
